home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
asmcode.lbr
/
INT14.AQM
/
INT14.ASM
Wrap
Assembly Source File
|
1985-06-03
|
23KB
|
624 lines
PAGE ,132
;
; INTERRUPT DRIVEN REPLACEMENT FOR IBM BIOS INTERRUPT 14
;
; WRITTEN BY BOB MURPHY, NOVEMBER 1984.
;
; YOU MAY WANT TO CHANGE THE COMMUNICATION BUFFER SIZE FOR COM1 AND COM2
; DEPENDING ON THE RECIEVE SPEED, AND TYPE OF COMMUNICATIONS YOU ARE
; DOING. THE 2K BUFFER IS GOOD FOR MOST 1200 BAUD APPLICATIONS, BUT WILL
; BE EXCESSIVELY BIG FOR HUMAN-SPEED COMMUNICATIONS. THIS WILL HANDLE
; CONTINUOUS DATA TRANSFER AT 9600 BAUD, ASSUMING THE APPLICATION USING IT
; CAN ALSO KEEP UP. YOU WILL WANT TO USE A LARGER BUFFER FOR HIGHER
; SPEEDS IF YOU ARE DOING FILE TRANSFERS.
;
; REDUCE THE COM2 BUFFERS TO A SINGLE BYTE IF THERE IS ONLY ONE COMM
; CHANNEL ON YOUR PC. DO NOT REMOVE THEM ENTIRELY.
;
;
;
; INPUT PARAMETERS ARE THE SAME AS THE REGULAR BIOS ROUTINES
; FOR FUNCTIONS (AH) = 0 TO (AH) = 4
;
; READ CHARACTER NOWAIT - AH = 5
; WILL READ A CHARACTER IF ONE IS AVAILABLE, AND RETURN IMMEDIATLY. THE
; STATUS BYTE IN THE AH MUST BE CHECKED BY THE USER. IF AH BIT 0 = 1, THEN
; THE AL CONTAINS A VALID CHARACTER. IF THAT BIT IS OFF, THEN THE AL CON-
; TAINS GARBAGE.
;
;
;
; THE STATUS RETURNED IS A BIT DIFFERENT THAN THE IBM ROUTINE IN THAT
; THE BREAK DETECT BIT (AH BIT 4) IS SET IF A COMM BUFFER OVERFLOW OCCURS. THE
; ERROR FLAGS DO NOT NECESSARILY APPLY TO THE CHARACTER BEING READ. THEY MAY
; HAVE BEEN SET BY A LATER ARRIVING CHARACTER. IN SHORT, THE ERROR BITS IN THE
; AH ARE NOT 'REAL TIME'. ANY TIME THE STATUS IS READ (ON ANY COMMAND) THE
; AH ERROR BITS ARE RESET FOR THE NEXT TIME.
;
; THE TX HOLD REG EMPTY BIT INDICATES THERE IS SPACE IN THE TX OUTPUT BUFFER
; THE TX SHIFT REG EMPTY BIT IS USED BY THE OUTBOUND SEND ROUTINE TO DETERMINE
; IF IT NEEDS TO SEND A CHARACTER TO INITIATE THE TRANSMISSION PROCESS. THIS
; BIT IS NOT USED BY ANY SOFTWARE THAT I KNOW OF, AND YOU SHOULD NOT USE IT.
;
;
;
PAGE
INCLUDE MACROS.ASM
BEGINCOM INT14
JMP INIT000 ;INITIALIZE VECTORS
BAUDTABL LABEL WORD
DW 1047 ;110 BAUD
DW 768 ;150 BAUD
DW 384 ;300 BAUD
DW 192 ;600 BAUD
DW 96 ;1200 BAUD
DW 48 ;2400 BAUD
DW 24 ;4800 BAUD
DW 12 ;9600 BAUD
ROUTINES LABEL WORD
DW COMMAND0 ;INITIALIZE COMMUNICATIONS CHANNEL
DW COMMAND1 ;TRANSMIT CHARACTER IN AL ACROSS CHANNEL
DW COMMAND2 ;WAIT FOR CHARACTER, AND RETURN IN AL
DW COMMAND3 ;RETURN STATUS WORD (2 BYTES)
DW COMMAND4 ;RECIEVE CHARACTER NOWAIT
MAXCMD DW ($-ROUTINES)/2 ;MAXIMUM COMMAND VALUE (MAX AH VALUE)
RS232_BASE EQU WORD PTR ES:0 ;ADDRESS OF RS232 BASE ADDR TBL IN SEG 40
RS232_TIM_OUT EQU BYTE PTR ES:07CH ;RS232 TIME OUT VALUE IN LO CORE
PAGE
COM0000: STI ;INTERRUPTS BACK ON
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH ES
PUSH DS ;SAVE WHAT WE CLOBBER
MOV BX,CS
MOV DS,BX ;MAKE THIS SEGMENT ADDRESSABLE
MOV SI,DX ;RS232 CARD SELECT TO SI
SHL SI,1 ;WORD OFFSET
MOV BX,40H ;ADDRESS OF BIOS CORE AREA
MOV ES,BX ;STASH IN DATA SEG
MOV DX,RS232_BASE [SI] ;GET RS232 BASE ADDRESS
OR DX,DX ;TEST FOR NO CARD PRESENT
JZ COM0090 ;RETURN
MOV BL,AH ;GET COMMAND INTO 2 BYTES
SUB BH,BH ; IN THE BX REGISTER
CMP BX,MAXCMD ;IS IT A VALID COMMAND?
JGE COM0090 ;NO-RETURN
SHL BX,1 ;MULTIPLY BY 2 FOR TRUE INDEX VALUE
CALL ROUTINES [BX] ;CALL APPROPRIATE COMMAND
;
; RETURN FROM INTERRUPT 14 - NORMAL OR ABEND
;
COM0090:
POP DS
POP ES
POP SI
POP DX ;RETURN FROM INT14
POP CX
POP BX
IRET
PAGE
;******************************************************************************
;
; INITIALIZE COMMUNICATIONS PORT
;
; DX HAS PORT ADDRESS, AH HAS PARMS. BITS 5-7 = BAUD RATE
; SI HAS CARD # (0-3) 3-4 = PARITY
; 2 = # STOP BITS
; 0-1 = # DATA BITS
;
;******************************************************************************
COMMAND0 PROC NEAR
MOV AH,AL ;SAVE INIT PARMS IN AH
ADD DX,03 ;POINT TO LINE CONTROL REGISTER (xFB)
MOV AL,80H ;OPEN DIVISOR LATCH
OUT DX,AL ;SET DLAB = 1
;
; DETERMINE BAUD RATE DIVISOR, AND PUT IT IN THE BX REG
;
MOV BL,AH ;BAUD RATE PARMS TO BL
MOV CL,04 ;SHIFT VALUE
ROL BL,CL ;MOVE TO ALIGN
AND BX,0EH ;BX HAS INDEX INTO BAUD RATE DIVISOR TABLE
MOV BX,BAUDTABL [BX] ;GET DIVISOR VALUE TO BX REGISTER
;
; SET BAUD RATE IN THE 8250
;
SUB DX,2 ;POINT TO DIVISOR LATCH MSB (xF9)
MOV AL,BH ;GET HI DIVISOR VALUE
OUT DX,AL ;STICK IN DIVISOR LATCH
DEC DX ;POINT TO DIVISOR LATCH LSB (xF8)
MOV AL,BL ;GET LOW ORDER DIVISOR VALUE
OUT DX,AL ;SAVE DIVISOR VALUE
;
; SET UP PARITY, STOP BITS, AND WORD LENGTH IN THE 8250
;
ADD DX,3 ;POINT TO LINE CTRL REG (xFB)
MOV AL,AH ;INPUT PARMS TO AL
AND AL,00011111B ;BAUD BITS OFF
OUT DX,AL ;SET UP LCR, CLOSE DIVISOR LATCH
;
; ENABLE THE 8250 INTERRUPTS
;
INC DX ;POINT TO MODEM CTRL REG (xFC)
MOV AL,00001101B ;SET UP OUT 2, DSR, AND RTS
OUT DX,AL ;ENABLE OUT 2 ON MCR (RQD FOR INTS)
SUB DX,3 ;POINT TO INT ENABLE REGISTER (xF9)
MOV AL,00001111B ;ENABLE ALL INTERRUPTS
OUT DX,AL ;PROGRAM THE IER
;
; ELIMINATE ANY PENDING INTS BEFORE IRQ CHANNEL ENABLE
;
DEC DX ;POINT TO RX REGISTER (xF8)
IN AL,DX ;KILL ANY RECIEVE INTERRUPT
INC DX
INC DX ;POINT TO IIR (xFA)
IN AL,DX ;KILL ANY THRE INTS
ADD DX,3 ;POINT TO LINE STATUS REG (xFD)
IN AL,DX ;KILL LINE STATUS INTERRUPTS
INC DX ;POINT TO MSR (xFE)
IN AL,DX ;KILL MODEM STATUS INTERRUPTS
AND AL,11110000B ;KEEP THE MODEM STATUS BITS
MOV COM1MODM [SI],AL ;ISR STATUS REFLECTS REAL WORLD
MOV AL,60H ;SET UP THRE,TSRE STATUS
MOV COM1LINE [SI],60H ;SET LINE STATUS BITS
;
; RESET BUFFER POINTERS BEFORE IRQ INITIALIZATION
;
MOV BX,COM1STRT [SI] ;GET START OF BUFFER (IN) POINTER
MOV COM1SPTR [SI],BX ;START POINTER RESET
MOV COM1EPTR [SI],BX ;END POINTER RESET
MOV BX,OUT1STRT [SI] ;GET START OF BUFFER (OUT) POINTER
MOV OUT1SPTR [SI],BX ;START POINTER RESET
MOV OUT1EPTR [SI],BX ;END POINTER RESET
;
; ENABLE THE IRQ CHANNEL ON THE 8259 INTERRUPT CONTROLLER
;
MOV CX,SI ;GET THE ADAPTER INVOLVED
SHR CL,1 ;MAKE VALUE 0 OR 1
NEG CL ;MAKE 0 OR -1 (-1 = COM2)
ADD CL,4 ;SET SHIFT COUNT TO 3 OR 4 (COM1=4)
MOV AH,0FEH ;SET UP MASK
ROL AH,CL ;ALIGN FOR INTERRUPT ENABLE ON 8259
CLI ;STOP INTS WHILE WE SCREW W/8259
IN AL,21H ;GET CURRENT INTERRUPT MASK BYTE
AND AL,AH ;ENABLE THE 8259 INTERRUPT
OUT 21H,AL ;RIGHT NOW
STI ;INTS BACK ON, COM1 OR 2 IS ACCEPTING
;
; RETURN FULL (2 BYTE) STATUS INFORMATION
;
CALL COMMAND3 ;DO A FULL STATUS REQUEST
RET ;AND WERE DONE
COMMAND0 ENDP
PAGE
;******************************************************************************
;
; SEND CHARACTER IN AL OVER COM LINE (DTR AND CTS ARE SET ON)
;
;******************************************************************************
COMMAND1 PROC NEAR
MOV BH,AL ;SAVE INCOMING CHARACTER
;
; TURN ON DTR AND CTS IF THEY ARE OFF
;
ADD DX,4 ;POINT TO MODEM CONTROL REGISTER (xFC)
IN AL,DX ;GET CURRENT MCR CONTENTS
OR AL,03 ;INSURE DTR AND RTS ARE ON
OUT DX,AL ;SEND BACK TO MCR
;
; CHECK DSR AND RTS FROM OTHER END
;
MOV AH,80H ;ASSUME A TIME OUT WILL OCCUR
CALL WAITDSR ;WAIT FOR DSR AND CTS FROM THE OTHER END
JC COM0295 ;DSR OR CTS NOT READY - GO ERROR
MOV BL,RS232_TIM_OUT [SI] ;GET TIME OUT VALUE FOR THIS PORT
SUB CX,CX ;DELAY
COM0220: TEST COM1LINE [SI],20H ;SPACE AVAIL IN BUFFER?
JNZ COM0230 ;YES-GO SEND THE CHARACTER
LOOP COM0220 ;ELSE-WAIT ON THE ISR TO GIVE US SOME ROOM
DEC BL ;DEC TIME OUT COUNT
JNZ COM0220 ;AND CONTINUE TO WAIT FOR XMIT
JMP SHORT COM0295 ;FALL THRU = TIME OUT ERROR
COM0230: MOV AL,BH ;RESTORE CHARACTER IN AL
;
CLI ;WERE GONNA TALK, SO DONT INTERRUPT
;THIS WILL HOLD OFF THE LAST THRE INT
TEST COM1LINE [SI],40H ;IS THE INTERRUPT ROUTINE RUNNING
JNZ COM0260 ;NO-TRANSMIT THE CHARACTER IN THIS RTN
; ;=40=TX BUFFER COMPLETLY EMPTY
;
; THE XMIT ISR IS GOING, BUFFER THE CHARACTER
;
MOV BX,OUT1EPTR [SI] ;GET END OF BUFFER POINTER
MOV [BX],AL ;QUEUE UP THE CHARACTER FOR TRANSMISSION
INC BX ;POINT TO NEXT AVL CHAR POS
CMP BX,OUT1ENDB [SI] ;POINTING OFF THE END?
JNE COM0240 ;NO-DONT REPOSITION
MOV BX,OUT1STRT [SI] ;ELSE-RESET TO BEGINNING OF BUFFER
COM0240: CMP BX,OUT1SPTR [SI] ;BUFFER OVERRUN OCCUR?
JNE COM0250 ;NO-THEN WERE OK
OR COM1LINE,20H ;POST BUFFER FULL FLAG
COM0250: STI ;WERE DONE-SO RESTORE INTERRUPTS
MOV OUT1EPTR [SI],BX ;SET BUFFER POSITION FOR NEXT CHARACTER
JMP SHORT COM0290 ;RESTORE INTS AND RETURN
;
; THE XMIT ISR IS NOT GOING, SO WE WILL SEND A CHARACTER TO START IT UP
;
COM0260:
AND COM1LINE [SI],10111111B ;TURN OFF TX BUFFER EMPTY (STRT ISR)
;THIS IS THE SHIFT REG EMPTY BIT
STI ;DONT NEED TO HOLD OFF INTS FOR THIS
SUB DX,4 ;POINT TO XMIT HOLDING REGISTER (xF8)
OUT DX,AL ;PUT CHAR IN TX HOLD REG. INTERRUPT WILL
;OCCUR WHEN IT HAS BEEN SENT.
COM0290: CALL HALFSTAT ;GET STATUS OF LINE
COM0295: RET
COMMAND1 ENDP
PAGE
;******************************************************************************
;
; RECIEVE CHARACTER FROM COMM-WAIT FOR COMM READY
;
;******************************************************************************
COMMAND2 PROC NEAR
MOV BL,RS232_TIM_OUT [SI] ;GET TIME OUT VALUE
SUB CX,CX
COM0320: TEST COM1LINE [SI],1 ;IS THERE A CHAR READY FLAG POSTED
JNZ COM0340 ;YES-GET OUT OF KILL TIME LOOP
LOOP COM0320 ;ELSE-WAIT ON CHARACTER
DEC BL ;DEC TIME OUT COUNT
JNZ COM0320 ;AND KEEP TRYING
CALL HALFSTAT ;GET LINE STATUS
OR AH,80H ;SET TIME OUT ERROR ALSO
JMP SHORT COM0390 ;FAIL WITH TIME OUT
COM0340: CALL COMMAND4 ;CALL RECIEVE CHARACTER NOWAIT
CALL HALFSTAT ;SET LINE STATUS FLAGS
COM0390: AND AH,10011110B ;ONLY RETURN ERROR BITS
RET ;RETURN WITH EITHER A CHARACTER OR AN ERROR
COMMAND2 ENDP
PAGE
;******************************************************************************
;
; COMM PORT STATUS REQUEST BX GETS CLOBBERED
;
;******************************************************************************
COMMAND3 PROC NEAR
CLI ;KILL RS232 INTERRUPTS
MOV AL,COM1MODM [SI] ;GET MODEM STATUS INTERRUPT DATA
MOV BL,AL ;SAVE MODEM STATUS DATA
AND AL,10110000B ;CLEAR THE DELTAS (AND STICKY RING INDICATOR)
MOV COM1MODM [SI],AL ;WE READ IT, SO WE CAN TURN OFF BITS
MOV AH,COM1LINE [SI] ;GET THE LINE STATUS FLAGS
MOV BH,AH ;COPY THEM
AND BH,01100001B ;KILL THE ERROR BITS (BUT DONT KILL RX AVL)
MOV COM1LINE [SI],BH ;SAVE CHANGE OF STATE IN CORE
STI ;INTS OK NOW THAT FLAGS HAVE BEEN GOTTEN
MOV AL,BL ;RESTORE THE MODEM STATUS DATA
RET ;AND RETURN TO CALLER
COMMAND3 ENDP
;
; CALL HALFSTAT TO RETURN LINE STATUS FLAGS IN AH. BH GETS CLOBBERED
;
HALFSTAT PROC NEAR ;TO GET LINE STATUS ONLY, COME HERE
CLI
MOV AH,COM1LINE [SI] ;GET THE LINE STATUS FLAGS
MOV BH,AH ;COPY THEM
AND BH,01100001B ;KILL THE ERROR BITS (BUT DONT KILL RX AVL)
MOV COM1LINE [SI],BH ;SAVE CHANGE OF STATE IN CORE
STI ;INTS OK NOW THAT FLAGS HAVE BEEN GOTTEN
RET ;AND RETURN TO CALLER
HALFSTAT ENDP
;
; WAIT FOR DSR AND RTS FROM THE OTHER END - IF TIME OUT, RETURN CARRY SET
;
WAITDSR PROC NEAR
MOV BL,RS232_TIM_OUT [SI] ;GET TIME OUT VALUE
SUB CX,CX ;LOOP VALUE
WAIT100: MOV AL,COM1MODM [SI] ;GET MODEM STATUS INTERRUPT DATA
AND AL,30H ;IS DSR AND CTS ON?
CMP AL,30H
JE WAIT200 ;YES-RETURN NORMAL
LOOP WAIT100 ;ELSE - TRY AGAIN
DEC BL ;DEC TIME OUT COUNTER
JNZ WAIT100 ;AND TRY 65536 MORE TIMES
STC ;FALL THRU = TIME OUT
WAIT200: RET ;RETURN TO CALLER
WAITDSR ENDP
PAGE
;*******************************************************************************
;
; RETRIEVE CHARACTER FROM INTERRUPT BUFFER
;
;
; RECIEVE CHARACTER NOWAIT. WILL RETURN CHARACTER IN AL IF ONE IS AVAILABLE.
; THE STATUS BYTE IN AH SHOULD BE TESTED FOR A X'01' TO SEE IF A CHARACTER WAS
; READ. IF BIT OFF, THEN AL = GARBAGE
;
;*******************************************************************************
COMMAND4 PROC NEAR
CLI ;DONT ALLOW RS232 INTS WHILE WE READ
MOV AH,COM1LINE [SI] ;GET COMM STATUS FLAG
AND COM1LINE [SI],61H ;AND ERASE ANY ERRS. LEAVE DATA AVL ALONE
MOV BX,COM1SPTR [SI] ;GET START OF BUFFER POINTER
CMP BX,COM1EPTR [SI] ;SAME AS END OF BUFFER POINTER?
JE COM0560 ;IF NO CHARS - KILL DATA AVL FLAG
;
; GET A CHARACTER FROM THE BUFFER
;
COM0540:
MOV AL,[BX] ;GET A CHARACTER FROM THE COMM BUFFER
INC BX ;
CMP BX,COM1ENDB [SI] ;OFF THE END?
JNE COM0550 ;NO-DONT RESET
MOV BX,COM1STRT [SI] ;ELSE-PICK UP START OF BUFFER ADDRESS
COM0550: MOV COM1SPTR [SI],BX ;SAVE UPDATED BUFFER POINTER
CMP BX,COM1EPTR [SI] ;DID WE JUST REMOVE THE LAST CHARACTER
JNE COM0580 ;NO-DONT KILL DATA AVAILABLE
;
; BUFFER CLEARED OUT - KILL THE DATA AVAILABLE FLAG
;
COM0560: AND COM1LINE [SI],0FEH ;ELSE-BUFFER EMPTY, DATA AVL OFF
AND AH,0FEH ;DO IN RETURN REG ALSO
;
; CHAR READ, IF ANY - SO ITS MILLER TIME FOR THIS ROUTINE
;
COM0580: STI ;RE-ALLOW INTS
RET ;AND HEAD OUT THE DOOR W/CHAR IN AL
COMMAND4 ENDP
PAGE
ORG 0400H
;*COMMISR**********************************************************************
;
; RS232 INTERRUPT HANDLER
;
;******************************************************************************
;
; POINTERS AND FLAGS FOR COMM BUFFERS
;
COM1SPTR DW COM1BUF ;START OF COMM BUFFER 1
COM2SPTR DW COM2BUF ;START OF COMM BUFFER 2
;
COM1EPTR DW COM1BUF ;END POINTER FOR COMM BUFFER 1
COM2EPTR DW COM2BUF ;END POINTER FOR COMM BUFFER 2
;
COM1STRT DW OFFSET COM1BUF ;ADDRESS OF COM1 BUFFER START
COM2STRT DW OFFSET COM2BUF ;ADDRESS OF COM2 BUFFER START
;
COM1ENDB DW OFFSET COM1END ;ADDRESS OF COM1 BUFFER END
COM2ENDB DW OFFSET COM2END ;ADDRESS OF COM2 BUFFER END
;
OUT1SPTR DW OUT1BUF ;START OF OUTPUT COMM BUFFER 1
OUT2SPTR DW OUT2BUF ;START OF OUTPUT COMM BUFFER 2
;
OUT1EPTR DW OUT1BUF ;END POINTER FOR OUT COMM BUFFER 1
OUT2EPTR DW OUT2BUF ;END POINTER FOR OUT COMM BUFFER 2
;
OUT1STRT DW OFFSET OUT1BUF ;ADDRESS OF OUTPUT COM1 BUFFER START
OUT2STRT DW OFFSET OUT2BUF ;ADDRESS OF OUTPUT COM2 BUFFER START
;
OUT1ENDB DW OFFSET OUT1END ;ADDRESS OF COM1 OUTPUT BUFFER END
OUT2ENDB DW OFFSET OUT2END ;ADDRESS OF COM2 OUTPUT BUFFER END
PAGE
COM1LINE DB 60H ;LINE STAT FOR COMM BUFFER 1
; 80 = TIME OUT (USED BY RD/WRT RTN)
; 40 = TSRE =1= LAST CHAR HAS BEEN SENT
; AND THE TX BUFFER IS EMPTY
; 20 = THRE =1= SPACE AVAILABLE IN TX BUF
; 10 = BREAK DETECT/BUFFER OVERFLOW
; 08 = FRAMING ERROR
; 04 = PARITY ERROR
; 02 = OVERRUN ERROR
; 01 = DATA AVAILABLE
COM1MODM DB 0 ;MODEM STATUS BYTE FOR COM1
; 80 = RLSD (CARRIER DETECT)
; 40 = RING INDICATOR
; 20 = DATA SET READY
; 10 = CLEAR TO SEND
; 08 = DELTA RLSD (CARRIER DETECT)
; 04 = DELTA RING INDICATOR
; 02 = DELTA DATA SET READY
; 01 = DELTA CLEAR TO SEND
COM2LINE DB 60H ;LINE STAT FOR COMM BUFFER 2
COM2MODM DB 0 ;MODEM STATUS BYTE FOR COM2
;
COMMBASE DW 0 ;STARTING I/O ADDRESS FOR COMM CARD
;
; INPUT BUFFER FOR COMM CHANNEL 1
;
COM1BUF DW 2048 DUP (?)
COM1END EQU $
;
; INPUT BUFFER FOR COMM CHANNEL 2
;
COM2BUF DW 2048 DUP (?)
COM2END EQU $
;
; OUTPUT BUFFER FOR COMM CHANNEL 1
;
OUT1BUF DW 256 DUP (?)
OUT1END EQU $
;
; OUTPUT BUFFER FOR COMM CHANNEL 2
;
OUT2BUF DW 256 DUP (?)
OUT2END EQU $
PAGE
;
; INTERRUPT SERVICE ROUTINES FOR COM1 AND COM2
;
ISRTABLE LABEL WORD ;INTERRUPT SERVICE ROUTINE ADDR TABLE
DW ISRMODEM ;MODEM STATUS ROUTINE (PRI 4)
DW ISRXMIT ;XMIT DATA (PRI 3)
DW ISRRECV ;RECIEVE DATA (PRI 2)
DW ISRLINE ;LINE STATUS (PRI 1)
ISR1000: STI ;ALLOW OTHER INTERRUPTS
PUSH SI
MOV SI,0 ;INDICATE COMM CARD 1
JMP SHORT ISR0100 ;SKIP TO MAINLINE
ISR2000: STI ;ALLOW OTHER INTERRUPTS
PUSH SI
MOV SI,2 ;INDICATE COMM CARD 2
;
; MAINLINE INTERRUPT RTN
;
ISR0100: PUSH AX ;SAVE ALL REGS USED
PUSH BX
PUSH CX
PUSH DX
PUSH DS
;
; SET UP BASE REGISTERS
;
MOV AX,40H ;ADDRESS OF RS232 CARD I/O PORT ADDRESSES
MOV DS,AX ;DS = CS FOR DATA BUFFERS
MOV DX,WORD PTR [SI] ;GET COMM CARD BASE ADDRESS
MOV AX,CS
MOV DS,AX ;DS POINTS TO PGM FOR USE OF COMM BUFFERS
MOV COMMBASE,DX ;SAVE COMM CARD BASE FOR SECOND TIME THROUGH
ISR0120: MOV DX,COMMBASE ;GET STARTING I/O ADDRESS FOR COMM CARD
INC DX
INC DX ;GET PORT FOR INT IDENTIFICATION REG
IN AL,DX ;GET IIR CONTENTS
TEST AL,1 ;IS AN INTERRUPT PENDING?
JNZ ISR0140 ;NO-EOI TO 8259 & LEST GET OUT OF HERE
CBW ;ELSE-GET INDEX INTO TABLE
MOV BX,AX ;COPY TO USEFUL REGISTER
CALL ISRTABLE [BX] ;CALL APPROPRIATE ROUTINE
JMP ISR0120 ;AND KEEP CHECKING UNTIL ALL INTS DONE
ISR0140:
;
; SIGNAL END OF INTERRUPT TO 8259
;
CLI ;KILL INTERRUPTS
MOV AL,20H ;NON-SPECIFIC EOI
OUT 20H,AL ;SEND IT
STI ;RE-ALLOW INTERRUPTS
;
; END OF INTERRUPT CODE
;
POP DS
POP DX
POP CX
POP BX
POP AX
POP SI
IRET
PAGE
;**ISRLINE*********************************************************************
;
; LINE STATUS ERROR HANDLER
;
;******************************************************************************
ISRLINE PROC NEAR
ADD DX,3 ;LINE STATUS REGISTER (xFD)
IN AL,DX ;GET STATUS
AND AL,00011110B ;MASK NON-ERROR BITS
OR COM1LINE [SI],AL ;AND SAVE IN COMM FLAGS
RET
ISRLINE ENDP
;**ISRRECV*********************************************************************
;
; INBOUND CHARACTER INTERRUPT SERVICE ROUTINE
;
;******************************************************************************
ISRRECV PROC NEAR
;
; GET INCOMING CHARACTER AND BUFFER IT
;
DEC DX
DEC DX ;RECEIVE BUFFER REGISTER (xF8)
SUB AH,AH ;SET FLAGS = 0
IN AL,DX ;GET INPUT CHARACTER
MOV BX,COM1EPTR [SI] ;COM-BUF END POINTER
MOV DX,BX ;SAVE POINTER BEFORE INCREMENT
INC BX ;BUMP POINTER
CMP BX,COM1ENDB [SI] ;PAST END?
JNE ISR0220 ;JUMP IF NOT
MOV BX,COM1STRT [SI] ;ELSE POINT TO START
ISR0220: CMP BX,COM1SPTR [SI] ;OVERFLOW IF HEAD = TAIL
JE ISR0240 ;OVERFLOW
MOV COM1EPTR [SI],BX ;AND NEW INPUT POINTER
MOV BX,DX ;GET UNBUMPED POINTER BACK
MOV [BX],AL ;NO OVERFLOW, SAVE CHAR IN COM1BUF
OR AH,1
JMP ISR0280 ;WERE ALL DONE RECIEVING CHARACTER
ISR0240: OR AH,10H ;SET OVERFLOW/BREAK FLAG
ISR0280: OR COM1LINE [SI],AH ;PUT IN LINE STATUS FIELD
RET
ISRRECV ENDP
PAGE
;**ISRXMIT*********************************************************************
;
; OUTBOUND CHARACTER INTERRUPT SERVICE ROUTINE
;
; POST XMIT SHIFT REG EMPTY WHEN LAST CHAR PLACED IN XMIT HOLD REG.
; KILL XMIT HOLD REG EMPTY WHEN XMIT BUFFER IS FILLED UP
;
;******************************************************************************
ISRXMIT PROC NEAR
;
MOV AH,40H ;ASSUME WE WILL SEND LAST CHARACTER
MOV BX,OUT1SPTR [SI] ;GET START OF BUFFER POINTER
CMP BX,OUT1EPTR [SI] ;IS THE BUFFER EMPTY?
JE ISR0480 ;YES-SKIP THE DATA TRANSMISSION
DEC DX
DEC DX ;POINT TO XMIT HOLDING REGISTER (xF8)
MOV AL,[BX] ;GET CHARACTER FROM BUFFER
OUT DX,AL ;SEND IT ON ITS WAY
INC BX ;BUMP THE OUTPUT BUFFER POINTER
CMP BX,OUT1ENDB [SI] ;POINTING AT THE END OF THE BUFFER
JNE ISR0420 ;NO-POINTER IS OK
MOV BX,OUT1STRT [SI] ;ELSE - POINT TO BUFFER START
ISR0420: MOV OUT1SPTR [SI],BX ;SAVE NEW BUFFER POINTER
OR AH,20H ;SEND BACK A TX HOLD REG EMPTY INDICATION
CMP OUT1EPTR [SI],BX ;DID WE JUST EMPTY THE BUFFER? *T
JE ISR0480 ;YES-THEN THERE WONT BE ANY MORE INTS *T
AND AH,10111111B ;AND SET BIT SAYS WERE OPERATING
ISR0480: OR COM1LINE [SI],AH ;STUFF IT IN THE FLAGS
RET
ISRXMIT ENDP
;**ISRMODEM********************************************************************
;
; MODEM STATUS INTERRUPT SERVICE ROUTINE
;
;******************************************************************************
ISRMODEM PROC NEAR
ADD DX,4 ;POINT TO MODEM STATUS REGISTER (xFE)
IN AL,DX ;GET CONTENTS & CLEAR INTERRUPT
MOV AH,AL
AND AH,11110000B ;GET ACTUAL SIGNAL LINE STATUS
OR AL,COM1MODM [SI] ;OR IN PREVIOUS LINE STATUS
AND AL,01001111B ;GET DELTA VALUES ALONE
;AND LEAVE RING INDICATOR ON
OR AL,AH ;SEVERAL DELTA VALUES, BUT ONLY CURRENT
MOV COM1MODM [SI],AL ; MODEM STATUS INTO MODEM STATUS FIELD
RET ;AND WERE DONE
ISRMODEM ENDP
PRGMEND EQU $ ;END OF CODE TO SAVE IN CORE
PAGE
;**NONRES**********************************************************************
;
; THE FOLLOWING IS NON-RESIDENT CODE
;
;******************************************************************************
;
; PROGRAM INITIALIZATION
;
INIT000: MOV DX,OFFSET COM0000 ;POINT TO START OF ROUTINE
@DOS 25H,14H ;RESET VECTOR 14
MOV DX,OFFSET ISR1000 ;ADDRESS OF COM 1 HANDLER
CLI ;STOP INTS DURING 8259 VECTOR UPDATE
@DOS 25H,0CH ;RESET VECTOR 0C (IRQ4-FOR COM1)
MOV DX,OFFSET ISR2000 ;ADDRESS OF COM 2 HANDLER
@DOS 25H,0BH ;RESET VECTOR 0B (IRQ3-FOR COM2)
STI
MOV DX,OFFSET PRGMEND ;POINT TO END OF CODE TO KEEP FOREVER
INT 27H ;TERMINATE & STAY RESIDENT
ENDCOM INT14